/* eslint-disable react/no-danger */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useRef } from 'react';
import { Collapse } from 'antd';
import hljs from 'highlight.js';
import MarkdownIt from 'markdown-it';
import setState from '@/assets/images/advanceReact/setState.png';
import transction from '@/assets/images/advanceReact/transction.png';

import 'highlight.js/styles/atom-one-light.css';
import './index.less';

const { Panel } = Collapse;
const mdParser = MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (error) {
        console.log(error);
      }
    }
    return ''; // 使用额外的默认转义
  },
});

export default function SetState() {
  const interviewQuestion =
    '```js' +
    `
    class App extends React.Component {
      state = { count: 0 };
      increment = () => {
        // 相当于这里上来会先上锁 isBatchingUpdates = true;
        console.log('increment setState前的count', this.state.count);
        this.setState({ count: this.state.count + 1 });
        console.log('increment setState后的count', this.state.count);
        // 执行完函数在放开 isBatchingUpdates = false;
      };

      triple = () => {
        console.log('triple setState前的count', this.state.count);
        this.setState({ count: this.state.count + 1 });
        this.setState({ count: this.state.count + 1 });
        this.setState({ count: this.state.count + 1 });
        console.log('triple setState后的count', this.state.count);
      };

      reduce = () => {
        // 相当于这里上来会先上锁 isBatchingUpdates = true;
        setTimeout(() => {
          // 此时isBatchingUpdates对内部setTimeout已经没影响
          console.log('reduce setState前的count', this.state.count);
          this.setState({ count: this.state.count - 1 });
          console.log('reduce setState后的count', this.state.count);
        }, 0);
        // 执行完函数在放开 isBatchingUpdates = false;
      };

      render() {
        return (
          <div>
            <button type="button" onClick={this.increment}>增加</button>
            <button type="button" onClick={this.triple}>增加三倍</button>
            <button type="button" onClick={this.reduce}>点我减少</button>
          </div>
        )
      }
    }
  `;

  const sourceCode1 =
    '```js' +
    `
    // 入口函数，相当于分发器的角色，根据参数分发至功能函数中
    ReactComponent.prototype.setState = function(partialState, callback) {
      this.updater.enqueueSetState(this, partialState);
      if(callback) {
        this.updater.enqueueCallback(this, callback, 'setState');
      }
    }

    // 将新的state放到组件的状态队列里，利用enqueueUpdate处理当前的组件实例
    enqueueSetState: function(publicInstance, partialState) {
      // 根据this拿到对应的组件实例
      var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');

      // 这个queue对应的就是一个组件实例的state数组
      var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
      queue.push(partialState);

      // enqueueUpdate用来处理当前的组件实例
      enqueueUpdate(internalInstance);
    }

    // 引出了batchingStrategy这个对象，isBatchingUpdates决定了是排队等待还是走更新流程
    function enqueueUpdate(component) {
      ensureInjected();
      // isBatchingUpdates标识着当前是否处于批量/更新组件的阶段
      if(!batchingStrategy.isBatchingUpdates) {
         // 不处于则立即更新
         batchingStrategy.batchedUpdates(enqueueUpdate, component);
         return;
      }
      dirtyComponents.push(component);
      if(component._updateBatchNumber == null) {
        component._updateBatchNumber = updateBatchNumber + 1;
      }
    }
  `;
  const sourceCode2 =
    '```js' +
    `
      // bactchingStrategy源码
      var ReactDefaultBatchingStrategy = {
        // 全局唯一标识
        isBatchingUpdates: false,

        // 发起更新动作的方法
        batchedUpdates: function(callback, a, b, c, d, e) {
          // 缓存锁变量
          var alreadyBatchingStrategy = ReactDefaultBatchingStrategy.isBatchingUpdates
          // 上锁
          ReactDefaultBatchingStrategy.isBatchingUpdates = true;

          if(alreadyBatchingStrategy) {
            callback(a, b, c, d, e);
          }else {
            // 启动事务，将callback放进事务执行
            transaction.perform(callback, null, a, b, c, d, e);
          }
        }
      }
    `;
  const core =
    '```js' +
    `
      var RESET_BATCHED_UPDATES = {
        initialize: emptyFuncton,
        close: function() {
          ReactDefaultBatchingStrategy.isBatchingUpdates = false;
        }
      }

      var FLUSH_BATCHED_UPDATES = {
        initialize: emptyFuncton,
        close: ReactUpdates.flushBactchedUpdates.bind(ReactUpdates)
      }

      var TRANSCTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
    `;

  return (
    <div className="advance-react-wrapper">
      <Collapse defaultActiveKey={['2', '3']}>
        <Panel header="1、面试题" key="1">
          <div
            className="code-wrapper"
            style={{ width: '60%' }}
            dangerouslySetInnerHTML={{
              __html: mdParser.render(interviewQuestion),
            }}
          />
          <p>输出：0 0 1 1 2 1</p>
          <p>
            在React钩子函数及合成事件中，它表现为异步，在setTimeout、setInterval
            等函数中，包括在DOM原生事件中，它都表现为同步。
          </p>
          <p>其原因是收到批量更新和事务机制的影响</p>
        </Panel>
        <Panel header="2、异步的动机和原理 -- 批量更新的艺术" key="2">
          <p>
            &emsp;每来一个setState，就把它塞进一个队列里“攒起来”，等时机成熟，再把“攒起来”的state结果做合并，最后只针对最新的state值走一次更新流程。
          </p>
        </Panel>
        <Panel header="3、同步现象背后的故事（从源码角度）" key="3">
          <p>
            并不是setTimeout改变了setState，而是setTimeout帮助setState“逃脱”了React对它的管控，只要是在React管控下的setState，一定是异步的。
          </p>
          <img src={setState} alt="" width="60%" />
          <div style={{ display: 'flex', gap: 10 }}>
            <div
              className="code-wrapper"
              style={{ width: '50%' }}
              dangerouslySetInnerHTML={{
                __html: mdParser.render(sourceCode1),
              }}
            />
            <div
              className="code-wrapper"
              style={{ width: '50%' }}
              dangerouslySetInnerHTML={{
                __html: mdParser.render(sourceCode2),
              }}
            />
          </div>
          <div style={{ marginTop: 20 }}>
            <h4>同步现象的本质:</h4>
            <p>ReactDefaultBatchingStrategy的2个wrapper</p>
            <div
              className="code-wrapper"
              dangerouslySetInnerHTML={{
                __html: mdParser.render(core),
              }}
            />
            <img src={transction} alt="" width="70%" />
          </div>
        </Panel>
      </Collapse>
    </div>
  );
}
